#include "stdafx.h"
#include "qirrlichtwidget.h"

SIrrlichtKey convertToIrrlichtKey( int key )
{
	SIrrlichtKey irrKey;
	irrKey.code = (irr::EKEY_CODE)(0);
	irrKey.ch = (wchar_t)(0);

	// Letters A..Z and numbers 0..9 are mapped directly
	if ( (key >= Qt::Key_A && key <= Qt::Key_Z) || (key >= Qt::Key_0 && key <= Qt::Key_9) )
	{
		irrKey.code = (irr::EKEY_CODE)( key );
		irrKey.ch = (wchar_t)( key );
	}
	else

		// Dang, map keys individually
		switch( key )
	{
		case Qt::Key_Up:
			irrKey.code = irr::KEY_UP;
			break;

		case Qt::Key_Down:
			irrKey.code = irr::KEY_DOWN;
			break;

		case Qt::Key_Left:
			irrKey.code = irr::KEY_LEFT;
			break;

		case Qt::Key_Right:
			irrKey.code = irr::KEY_RIGHT;
			break;
	}
	return irrKey;
}

QIrrlichtWidget::QIrrlichtWidget(QWidget *parent)
	: QWidget(parent),m_device(NULL),m_camera(NULL)
{
	setAttribute(Qt::WA_PaintOnScreen);
	setAttribute(Qt::WA_OpaquePaintEvent);
	setAttribute(Qt::WA_NoBackground);
	//setAttribute(Qt::WA_KeyboardFocusChange);
	
	//setAttribute(Qt::WA_MouseNoMask);
	//setAttribute(Qt::WA_MouseTracking);
	//setAttribute(Qt::WA_TransparentForMouseEvents);

	grabKeyboard();
}

QIrrlichtWidget::~QIrrlichtWidget()
{
	if (m_device != NULL)
	{
		m_device->closeDevice();
		m_device->drop();
	}
}

irr::IrrlichtDevice* QIrrlichtWidget::getIrrlichtDevice()
{
	return m_device;
}

void QIrrlichtWidget::init()
{
	if (m_device != NULL)
	{
		return;
	}

	m_qiEventReceiver = new QIEventReceiver(this);

	irr::SIrrlichtCreationParameters params;
	params.AntiAlias		= 0;
	params.Bits				= 32;
	params.DeviceType		= irr::EIDT_WIN32;
	params.Doublebuffer		= true;
	params.DriverType		= irr::video::EDT_DIRECT3D9;
	params.EventReceiver	= m_qiEventReceiver;
	params.Fullscreen		= false;
	params.HighPrecisionFPU	= false;
	params.IgnoreInput		= false;
	params.LoggingLevel		= irr::ELL_INFORMATION;
	params.Stencilbuffer	= true;
	params.Stereobuffer		= false;
	params.Vsync			= false;
	params.WindowId			= (void* )winId();
	params.WindowSize.Width	= width();
	params.WindowSize.Height = height();
	params.WithAlphaChannel = false;
	params.ZBufferBits		= 16;

	m_device = createDeviceEx(params);

	if (m_device)
	{
		m_camera = m_device->getSceneManager()->addCameraSceneNode(0,
			irr::core::vector3df(0, 30, -40), irr::core::vector3df(0, 5, 0));
	}
	//connect(this, &QIrrlichtWidget::updateIrrlichtQuery, this, &QIrrlichtWidget::updateIrrlicht);

	startTimer(30);
}

void QIrrlichtWidget::updateIrrlicht( irr::IrrlichtDevice* device )
{
	if (m_device != NULL)
	{
		m_device->getTimer()->tick();
		irr::video::SColor color(255, 100, 100, 140);

		m_device->getVideoDriver()->beginScene(true, true, color);
		m_device->getSceneManager()->drawAll();
		m_device->getVideoDriver()->endScene();
	}
}

void QIrrlichtWidget::paintEvent( QPaintEvent* event )
{
	if (m_device != NULL)
	{
		updateIrrlicht(m_device);
	}
}

void QIrrlichtWidget::timerEvent( QTimerEvent* event )
{
	if (m_device != NULL)
	{
		updateIrrlicht(m_device);
	}

	event->accept();
}

void QIrrlichtWidget::sendKeyEventToIrrlicht( QKeyEvent* event, bool pressedDown )
{
	if (Qt::Key_Escape == event->key())
	{
		if (getIrrlichtDevice())
		{
			irr::scene::ICameraSceneNode * camera =
				getIrrlichtDevice()->getSceneManager()->getActiveCamera();
			if (camera)
			{
				camera->setInputReceiverEnabled( false);
				//camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() );
			}
			//return true;
		}
		setInIrrlicht(false);
		releaseMouse();
		return;
	}

	irr::SEvent irrEvent;

	irrEvent.EventType = irr::EET_KEY_INPUT_EVENT;

	SIrrlichtKey irrKey = convertToIrrlichtKey( event->key() );

	if ( irrKey.code == 0 ) return; // Could not find a match for this key

	irrEvent.KeyInput.Key = irrKey.code;
	irrEvent.KeyInput.Control = ((event->modifiers() & Qt::ControlModifier) != 0);
	irrEvent.KeyInput.Shift = ((event->modifiers() & Qt::ShiftModifier) != 0);
	irrEvent.KeyInput.Char = irrKey.ch;
	irrEvent.KeyInput.PressedDown = pressedDown;

	m_device->postEventFromUser( irrEvent );
}

void QIrrlichtWidget::keyPressEvent( QKeyEvent* event )
{
	if ( m_device != 0 )
	{
		sendKeyEventToIrrlicht( event, true );
	}
	event->ignore();
}

void QIrrlichtWidget::keyReleaseEvent( QKeyEvent* event )
{
	if ( m_device != 0 )
	{
		sendKeyEventToIrrlicht( event, false );
	}
	event->ignore();
}

void QIrrlichtWidget::sendMouseEventToIrrlicht( QMouseEvent* event, bool pressedDown )
{
	irr::SEvent irrEvent;

	irrEvent.EventType = irr::EET_MOUSE_INPUT_EVENT;

	switch(event->type())
	{
	case QEvent::MouseMove:
		irrEvent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
		break;
	default:
		switch ( event->button() )
		{
		case Qt::LeftButton:
			irrEvent.MouseInput.Event = pressedDown? irr::EMIE_LMOUSE_PRESSED_DOWN:irr::EMIE_LMOUSE_LEFT_UP;
			if (pressedDown)
			{
				if (!isInIrrlicht())
				{
					setInIrrlicht(true);
					if (getIrrlichtDevice())
					{
						irr::scene::ICameraSceneNode * camera =
							getIrrlichtDevice()->getSceneManager()->getActiveCamera();
						if (camera)
						{
							camera->setInputReceiverEnabled( true);
							//camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() );
						}
						//return true;
					}
				}			
			}
			break;

		case Qt::MidButton:
			irrEvent.MouseInput.Event = pressedDown? irr::EMIE_MMOUSE_PRESSED_DOWN:irr::EMIE_MMOUSE_LEFT_UP;
			break;

		case Qt::RightButton:
			irrEvent.MouseInput.Event = pressedDown? irr::EMIE_RMOUSE_PRESSED_DOWN:irr::EMIE_RMOUSE_LEFT_UP;
			break;

		default:
			return; // Cannot handle this mouse event
		}
	}



	irrEvent.MouseInput.X = event->x();
	irrEvent.MouseInput.Y = event->y();
	//irrEvent.MouseInput.X = 1;
	//irrEvent.MouseInput.Y = 1;
	irrEvent.MouseInput.Wheel = 0.0f; // Zero is better than undefined

	if (m_device->postEventFromUser( irrEvent ))
	{
		event->accept();
	}

}

void QIrrlichtWidget::mousePressEvent( QMouseEvent* event )
{
	if ( m_device != 0 )
	{
		sendMouseEventToIrrlicht( event, true );
	}
	event->ignore();
}

void QIrrlichtWidget::mouseReleaseEvent( QMouseEvent* event )
{
	if ( m_device != 0 )
	{
		sendMouseEventToIrrlicht( event, false );
	}
	event->ignore();
}

void QIrrlichtWidget::wheelEvent( QWheelEvent* event )
{
	if ( m_device != 0 && event->orientation() == Qt::Vertical )
	{
		irr::SEvent irrEvent;

		irrEvent.EventType = irr::EET_MOUSE_INPUT_EVENT;

		irrEvent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;
		irrEvent.MouseInput.X = 0; // We don't know these,
		irrEvent.MouseInput.Y = 0; // but better zero them instead of letting them be undefined
		irrEvent.MouseInput.Wheel = event->delta() / 120.0f;

		m_device->postEventFromUser( irrEvent );
	}
	event->ignore();
}


void QIrrlichtWidget::mouseMoveEvent( QMouseEvent* event )
{
	if ( m_device != 0 )
	{
		sendMouseEventToIrrlicht( event, false );
	}
	event->ignore();
}

bool QIrrlichtWidget::isInIrrlicht()
{
	return m_inIrrlicht;
}

void QIrrlichtWidget::setInIrrlicht( bool isIn )
{
	m_inIrrlicht = isIn;
}







bool QIEventReceiver::OnEvent( const irr::SEvent& event )
{
	if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
		event.KeyInput.PressedDown == false)
	{
		if (event.KeyInput.Key == irr::KEY_KEY_Q)
		{
			if (m_widget->m_device)
			{
				irr::scene::ICameraSceneNode * camera =
					m_widget->m_device->getSceneManager()->getActiveCamera();
				if (camera)
				{
					camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() );
				}
				return true;
			}
		}


	}

	if (m_widget->m_device)
	{
		irr::scene::ICameraSceneNode * camera = m_widget->m_device->getSceneManager()->getActiveCamera();
		if (camera)
			return camera->OnEvent(event);
	}


	return false;
}
